#include "EstrategiaAlmacenamientoRegistros.h"
#include "Registro.h"
#include <sstream>
#include "Excepciones.h"

namespace Toolkit
{

EstrategiaAlmacenamientoRegistros::EstrategiaAlmacenamientoRegistros(
		const unsigned long int &tamanoBloque,
		const TipoSerializacion &tSerializacion) :
	EstrategiaAlmacenamiento(tamanoBloque)
{
	this->tSerializacion = tSerializacion;
}

EstrategiaAlmacenamientoRegistros::~EstrategiaAlmacenamientoRegistros()
{
}

unsigned long int EstrategiaAlmacenamientoRegistros::guardarDato(
		Almacenamiento &almacenamiento, const Dato &dato, const Clave &clave,
		WrapperComponente &wrapper)
{
	if (datoAuxiliar == NULL)
	{
		datoAuxiliar = dato.clonar();
	}

	Registro registro(tSerializacion);

	registro.setDato(dato);

	stringstream serializacion;
	wrapper.setComponente(&registro);
	wrapper.serializar(serializacion, tSerializacion);

	if (serializacion.str().size() > almacenamiento.getTamano())
	{
		throw DesbordeDeDatoException();
	}

	return almacenamiento.guardarDato(serializacion);
}

unsigned long int EstrategiaAlmacenamientoRegistros::modificarDato(
		Almacenamiento &almacenamiento, const Dato &dato, const Clave &clave,
		const unsigned long int posicion, WrapperComponente &wrapper)
{
	if (datoAuxiliar == NULL)
	{
		datoAuxiliar = dato.clonar();
	}

	Registro registro(tSerializacion);

	registro.setDato(dato);

	stringstream serializacion;
	wrapper.setComponente(&registro);
	wrapper.serializar(serializacion, tSerializacion);

	if (serializacion.str().size() > almacenamiento.getTamano())
	{
		throw DesbordeDeDatoException();
	}

	almacenamiento.guardarDato(serializacion, posicion);

	return posicion;
}

bool EstrategiaAlmacenamientoRegistros::recuperarDato(
		Almacenamiento &almacenamiento, const unsigned long int posicion,
		Dato &dato, const Clave &clave, WrapperComponente &wrapper)
{
	if (datoAuxiliar == NULL)
	{
		datoAuxiliar = dato.clonar();
	}

	stringstream serializacion;
	almacenamiento.recuperarDato(posicion, serializacion);

	Registro registro(tSerializacion);

	wrapper.setComponente(&registro);

	wrapper.hidratar(serializacion, dato, tSerializacion);

	if (registro == clave)
	{
		registro.hidratarDato(dato);//esto hidrata el dato.
	}

	return registro == clave;
}

void EstrategiaAlmacenamientoRegistros::eliminarDato(
		Almacenamiento &almacenamiento, const long unsigned int posicion,
		Dato &dato, const Clave &clave, WrapperComponente &wrapper)
{
	if (datoAuxiliar == NULL)
	{
		datoAuxiliar = dato.clonar();
	}

	stringstream serializacion;
	almacenamiento.eliminarDato(posicion, serializacion);

	Registro registro(tSerializacion);

	registro.setDato(dato);//esto clona el dato
	wrapper.setComponente(&registro);
	wrapper.hidratar(serializacion, dato, tSerializacion);
	registro.hidratarDato(dato);//esto hidrata el dato.

}

void EstrategiaAlmacenamientoRegistros::recuperarComponente(
		Almacenamiento &almacenamiento, const unsigned long int &posicion,
		WrapperComponente &wrapper)
{
	stringstream stream;
	almacenamiento.recuperarDato(posicion, stream);

	Registro *registro = new Registro(tSerializacion);
	wrapper.setComponente(registro);
	wrapper.hidratar(stream, *datoAuxiliar, tSerializacion);

}

void EstrategiaAlmacenamientoRegistros::guardarComponente(
		Almacenamiento &almacenamiento, const unsigned long int &posicion,
		WrapperComponente &wrapper)
{
	stringstream stream;
	wrapper.serializar(stream, tSerializacion);

	almacenamiento.guardarDato(stream, posicion);
}

unsigned long int EstrategiaAlmacenamientoRegistros::guardarComponente(
		Almacenamiento &almacenamiento, WrapperComponente &wrapper)
{
	stringstream stream;
	wrapper.serializar(stream, tSerializacion);

	return almacenamiento.guardarDato(stream);
}

void EstrategiaAlmacenamientoRegistros::eliminarComponente(
		Almacenamiento &almacenamiento, const unsigned long int &posicion,
		WrapperComponente &wrapper)
{
	stringstream stream;
	almacenamiento.eliminarDato(posicion, stream);

	wrapper.hidratar(stream, *datoAuxiliar, BINARIO);

}

}
